package controllers

import models.users._

import java.sql.Timestamp
import java.time.LocalDateTime
import javax.inject._
import play.api.Logging
import play.api.cache.SyncCacheApi
import play.api.data.Form
import play.api.data.Forms._
import play.api.libs.json.Json
import play.api.mvc._
import security.access.PermissionAccess
import services.dingtalk.DingtalkService

import java.io.ByteArrayOutputStream
import scala.concurrent.{ExecutionContext, Future}
import scala.concurrent.duration._

/**
 * This controller creates an `Action` to handle HTTP requests to the
 * application's home page.
 */
@Singleton
class UsersController @Inject()(
                                 usersRepo: UserGroupRepository,
                                 cc: MessagesControllerComponents,
                                 dingTalk: DingtalkService,
                                 cache: SyncCacheApi,
                                 config: DingtalkService
                               )(
                                 implicit exec: ExecutionContext,
                                 parser: BodyParsers.Default
                               )
  extends AbstractController(cc) with play.api.i18n.I18nSupport with Logging {

  implicit val myCustomCharset = Codec.javaSupported("gb18030")
  val sec = security.Encode
  /**
   * The mapping for the person form.
   */
  val userForm: Form[UserLoginForm] = Form {
    mapping(
      "accid" -> default(number, (0)),
      "p1" -> nonEmptyText,
      "p2" -> nonEmptyText,
      "loginCpacha" -> default(text, "")
    )(UserLoginForm.apply)(UserLoginForm.unapply)
  }

  /**
   * Create an Action to render an HTML page with a welcome message.
   * The configuration in the `routes` file means that this method
   * will be called when the application receives a `GET` request with
   * a path of `/`.
   */
  def index1() = checkLogin(parser, exec) { implicit request =>
    request.session.get("accid")
      .map(id => Ok(views.html.users.index(s"User.$id")))
      .getOrElse(Unauthorized(views.html.users.index("User.nologin")))
  }

  def index() =checkLogin(parser, exec){implicit request =>
    Ok(views.html.dingtalk.dingtalkpc("cropid","company"))
  }

  def index_m() = Action { implicit  request =>
    Ok(views.html.dingtalk.dingtalkmobile(""))
  }

  def login(code:String ,company:String) = Action { implicit request =>
    val session_id = request.headers.get("X-Session-Id")
    println("session_id: ", session_id)
    Ok(views.html.users.login1(code,company))
  }

  def getCpacha() = Action { implicit request =>
    import javax.imageio.ImageIO
    import java.awt.image.BufferedImage
    val generatorRotateVCodeImage = services.CpachaUtil.get()
    val code = generatorRotateVCodeImage._2.toUpperCase
    val codevalue = code.hashCode.toString
    var stream = new ByteArrayOutputStream()
    ImageIO.write(generatorRotateVCodeImage._1, "gif", stream)
    cache.set("loginCpacha-" + code, codevalue, 1.minutes)
    Ok(stream.toByteArray)
  }

  def authUser(url: String) = Action(parse.json).async { implicit request =>
    val p = request.body
    val person = UserLoginForm(p1 = p("p1").as[String], p2 = p("p2").as[String], cpacha = p("loginCpacha").as[String].toUpperCase)
    val cpache = cache.get[String]("loginCpacha-" + person.cpacha).getOrElse("0").toInt
    logger.debug(person.toString + " person.cpacha.hashCode:" + person.cpacha.hashCode + " cpache.hashCode:" + cpache.toString)
    if (person.cpacha.hashCode != cpache) {
      Future(Ok(Json.obj("success" -> false,"message" -> "验证码错误，请点击图片刷新后重试！")))
    } else {
      usersRepo.userFindByNamePwd(mobile = person.p1).map { r =>
        // If successful, we simply redirect to the index page.
        if (r.nonEmpty) {
          val account = r.head
          lazy val access = PermissionAccess.check(account.permission, "nologin")
          //(1.id, 2.username, 3.password, 4.lastLoginDate, 5.userid, 6.is_admin)
          lazy val password = account.password
          lazy val checkpassword = person.p2 + account.userid
          lazy val pwdVerify = sec.pwdVerify(password, checkpassword)
          if ((!access) && pwdVerify) {
            val ld = Timestamp.valueOf(LocalDateTime.now())
            usersRepo.userUpdateLastLoginDate(account.id, Option(ld))
            val surl = request.session.get("surl")
            val resUrl = if (url.nonEmpty) {
              url
            } else if (surl.isEmpty) {
              "/users"
            }
            else {
              surl.get
            }
            Ok(
              //(1.id, 2.username, 3.password, 4.lastLoginDate, 5.userid, 6.is_admin)
              Json.obj(
                "url" -> resUrl,
                "accid" -> account.id.getOrElse(0).toString,
                "uname" -> account.username,
                "userid" -> account.userid,
                "sign" -> (account.username + account.password + ld.getTime).hashCode.toString,
                "admin" -> account.permission,
                "success" -> true,
                "message" -> "login success!"
              )
            )
              //            Redirect(resUrl).flashing("success" -> s"Hi, ${account._2}")
              .withSession(
                "accid" -> account.id.getOrElse(0).toString,
                "uname" -> account.username,
                "userid" -> account.userid,
                "sign" -> (account.username + account.password + ld.getTime).hashCode.toString,
                "admin" -> account.permission.toString
              )
              .withHeaders(("Token","hello,token"))

          } else {
            Ok(Json.obj("success" -> false,"message" -> "user.wrong"))
          }
        }
        else {
          Ok(Json.obj("success" -> false,"message" -> "用户不存在！"))
          //            Redirect(routes.UsersController.login()).flashing("success" -> "user.wrong")
        }
      }
    }
  }

  def updatePWD() = checkLogin(parser, exec) { implicit request =>
    Ok(views.html.users.updatepwd("userForm"))
  }

  //  def updatedPWD1() = checkLogin(parse.json, exec).async { implicit request =>
  //    val p = request.body
  //    val person = UserLoginForm(p1 = p("p1").as[String], p2 = p("p2").as[String])
  //    logger.debug(person.toString)
  //    val accId = request.session.get("accid").getOrElse("-1").toInt
  //    val userid = request.session.get("userid")
  //    //        println(p)
  //    if (userid.nonEmpty && person.p1 == person.p2) {
  //      val password = person.p1
  //      usersRepo.userUpdatePassword(accId, sec.pwdHashed(password + userid.get)).map {
  //        r =>
  //          if (r == 1) {
  //            Ok(Json.obj("message" -> "update password Ok!")).withNewSession
  //          }
  //          else Ok(Json.obj("message" -> "update password false!"))
  //      }
  //    } else Future(Ok(Json.obj("message" -> "update password false!!")))
  //
  //  }

  def pwdUpdated() = checkLogin(parse.json, exec).async { implicit request =>
    val p = request.body
    logger.debug(p.toString)
    val person = UserLoginForm(accid = p("accid").asOpt[Int].getOrElse(0), p1 = p("p1").as[String], p2 = p("p2").as[String])
    logger.debug(person.toString)
    lazy val is_admin = PermissionAccess.check(request.session.get("admin").getOrElse("0").toInt, "admin")
    val accid = request.session.get("accid").getOrElse("0").toInt
    val accId: Int = if (person.accid != 0 && is_admin) person.accid
    else accid
    usersRepo.userFindByNamePwd(id = accId).flatMap {
      user =>
        logger.debug(s"${user.mkString(",")}")
        if (user.nonEmpty && person.p1 == person.p2) {
          val account = user.head
          val password = person.p1
          //(1.id, 2.username, 3.password, 4.lastLoginDate, 5.userid, 6.is_admin)
          usersRepo.userUpdatePassword(accId, sec.pwdHashed(password + account.userid)).map {
            r =>
              if (r == 1) {
                val res = Ok(Json.obj("message" -> s"${account.username} update password Ok!"))
                if (accid == person.accid) res.withNewSession
                else res
              }
              else Ok(Json.obj("message" -> s"${account.username} update password false!"))
          }
        } else Future(Ok(Json.obj("message" -> s"${person.accid} input password false!!")))
    }


  }

  private val getCorpId = (com: String) => config.getDingtalkConfig(com).CorpId

  def indexPCAsCompany(company: String) = {
    val cropid = getCorpId(company)
    println(s"indexPCAsCompany company = $company, cropid = $cropid")
    login(cropid, company)
  }

  def indexMobileAsCompany(company: String) = {
    val cropid = getCorpId(company)
    println(s"indexPCAsCompany company = $company, cropid = $cropid")
//    login(cropid, company)
    index_m()
  }

  def dingTalkAuth(code: String,company:String) = Action.async { implicit request =>
    println(s"[${LocalDateTime.now()}]code = $code,company = $company")
//    val company = "wuyang"
    val userid = dingTalk.getUserInfo(company, code)
    logger.debug(s"userid = $userid")
    usersRepo.userFindByNamePwd(userid = userid).map { r =>
      if (r.nonEmpty) {
        val ld = Timestamp.valueOf(LocalDateTime.now())
        val account = r.head
        logger.debug(account.toString())
        //(1.id, 2.username, 3.password, 4.lastLoginDate, 5.userid, 6.is_admin)
        usersRepo.userUpdateLastLoginDate(account.id, Option(ld))
        Ok(
          Json.obj(
            "accid" -> account.id.getOrElse(0).toString,
            "uname" -> account.username,
            "userid" -> account.userid,
            "sign" -> (account.username + account.password + ld.getTime).hashCode.toString,
            "admin" -> account.permission.toString,
            "success" -> true,
            "message" -> "login success!"
          )
        )
          //      Redirect(routes.HomeController.indexMobile())
//          .flashing("success" -> s"Hi, ${account.username}")
          .withSession(
            "accid" -> account.id.getOrElse(0).toString,
            "uname" -> account.username,
            "userid" -> account.userid,
            "sign" -> (account.username + account.password + ld.getTime).hashCode.toString,
            "admin" -> account.permission.toString
          )
          .withHeaders(("Token","hello,token"))
      } else {
        Ok("login false")
      }
    }
  }

  def logout() = Action {
    Redirect(routes.UsersController.index()).withNewSession
  }

  def register() = Action.async { implicit request =>
    //默认导入密码：123
    usersRepo.userCreateUpdate(User(id = None, password = "$argon2i$v=19$m=65536,t=4,p=2$TnBxMGdiWjlPWHJpS0pPcGhISjBoZz09$2BKTmOob/PjBZjgMqqTxMzsY6/qqxJYIJ3Vpcyfq5ms",
      username = "admin", position = Some("administrators"), email = Some("admin@email.eml"),
      is_active = true, userid = "userid", unionid = "unionid", tel = Some("tel"),
      workPlace = Some("workPlace"), mobile = "mobile", orgEmail = Some("admin@orgEmail.eml"), company = 0
    )).map(f => Ok(Json.obj("success" -> true, "message" -> s"created user id is ${f}")))
  }

  def oauth() = Action {
    Ok("oauth")
  }


}

case class UserLoginForm(accid: Int = 0, p1: String, p2: String, cpacha: String = "")